package org.framework.common.api.query;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.framework.common.api.query.Criterion.Operator;
import org.springframework.data.jpa.domain.Specification;

/**
 * 条件表达式容器
 * <p>描述: </p>
 * <p>Company: Professional</p>
 * @author chanlong(陈龙)
 * @date 2016年1月18日 下午4:39:17
 * @version 1.0.2016
 */
public class Criteria<T> implements Specification<T> {

	private List<Criterion> and = new ArrayList<Criterion>();
	private List<Criterion> or = new ArrayList<Criterion>();
	
	/**
	 * @see org.springframework.data.jpa.domain.Specification#toPredicate(javax.persistence.criteria.Root, javax.persistence.criteria.CriteriaQuery, javax.persistence.criteria.CriteriaBuilder)
	 * @author chanlong(陈龙)
	 * @date 2016年1月18日 下午4:40:18
	 */
	@Override
	public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
		return createPredicates(root, query, builder);
	}

	/**
	 * 添加条件.
	 * @param criterion
	 * @author chanlong(陈龙)
	 * @date 2016年1月18日 下午4:48:48
	 */
	public void add(Criterion criterion, Operator operator) {
		if (criterion != null) {
			switch (operator) {
				case OR:
					or.add(criterion);
				break;
				default:
					and.add(criterion);
				break;
			}
		}
	}
	
	/**
	 * 清空条件.
	 * @author chanlong(陈龙)
	 * @date 2016年1月18日 下午4:50:11
	 */
	public void clear(){
		and.clear();
		or.clear();
	}
	
	// 创建条件数组
	private Predicate createPredicates(final Root<T> root, final CriteriaQuery<?> query, final CriteriaBuilder builder){
		Predicate predicate = builder.conjunction();
		
		for(int i = 0, size = and.size(); i < size; i++){
			predicate = builder.and(predicate, and.get(i).toPredicate(root, query, builder));
		}
		
		Predicate[] orarray = new Predicate[or.size()];
		for(int i = 0, size = or.size(); i < size; i++){
			orarray[i] = or.get(i).toPredicate(root, query, builder);
		}
		
		if(orarray.length > 1){
			predicate = builder.and(predicate, builder.or(orarray));
		}else if(orarray.length == 1){
			predicate = builder.and(predicate, orarray[0]);
		}
		return predicate;
	}
}
